#ifndef HRSYSTEM_H
#define HRSYSTEM_H

#include "company.h"
#include "common.h"

/**
 * This class is an exception class for handling bad inputs
 */

class EmployeeIdRedifined : public FailureException {};
class EmployeeIdNotDefined : public FailureException {};
class EmployeeIdIllegal : public InvalidInputExcpetion {};
class CompanyIndexOutOfRange : public InvalidInputExcpetion {};
class CompanyDoesNotExist : public FailureException {};

/**
 * This class is a wrapper class for a collection of companies
 */
class HRSystem
{
public:
	/**
	 * Constructor: Create a certain amount of companies (K)
	 * \param The number of companies to be created
	 * \remarks Complexity is O(K) since there are K O(1) constructors called
	 */
	HRSystem(int numberOfCompanies);

	/**
	 * Destructor
	 * \remarks Complexity is O(n+K) where n is total amount of employees in all
	 * of the companies and K is the amount of companies
	 */
	~HRSystem();
public:

	/**
	 * This function puts the employee in a company with a certain salary
	 * \param The employee number
	 * \param The salary of the employee
	 * \param The company number to be hired on
	 * \remarks Complexity is O(log n) where n is number of employees in all of
	 * the companies
	 */
	void HireEmployee(int employeeId,
					  const rational::Rational& salary,
					  int companyId);

	/**
	 * This function removes an employee from a company
	 * \param The employee number
	 * \param The salary of the employee
	 * \param The company number to be hired on
	 * \remarks Complexity is O(log n) where n is number of employees in all of
	 * the companies
	 */
	void FireEmployee(int employeeId, int companyId);

	/**
	 * This function finds the company number of a certain employee
	 * \param The employee number
	 * \remarks Complexity is O(log n) where n is number of employees in all of
	 * the companies
	 */
	int GetEmployer(int employyId) const;

	/**
	 * This function finds the salary of a certain employee
	 * \param The employee number
	 * \remarks Complexity is O(log n) where n is number of employees in all of
	 * the companies
	 */
	rational::Rational GetSalary(int employeeId) const;

	/**
	 * This function gets the median salary of a certain company
	 * \param The company number to get its median salary
	 * \remarks Complexity is O(1) since the median salray is always kept and
	 * maintained throughout the code and runtime
	 */
	rational::Rational GetMedianSalary(int companyId) const;

	/**
	 * This function gets the highest salary of a certain company
	 * \param The company number to get its highest salary
	 * \remarks Complexity is O(1) since the highest salray is always kept and
	 * maintained throughout the code and runtime
	 */
	rational::Rational GetHeighestSalary(int companyId) const;

	/**
	 * This function updates the salaries for an entire company
	 * \param The company number to update its salaries
	 * \param The factor to update to
	 * \remarks Complexity is O(1) since we change the company salary factor
	 */
	void UpdateSalaries(int companyId, const rational::Rational& factor);

	/**
	 * This function merges two companies into one, moving all the employees and
	 * their salaries
	 * \param The number of company which is buying
	 * \param The number of company which is selling
	 * \remarks Complexity is O(Na+Nb) where Na is the number of employees in
	 * first company and Nb is the number of employees in the second company
	 */
	void Merger(int buyingCompany, int sellingCompany);

private:
	shared_ptr<Company> GetCompany(int companyId) const;
	shared_ptr<Employee> GetEmployee(int employee) const;

private:
	myVector<shared_ptr<Company> > _Companies;
	AVLTree<int, shared_ptr<Employee> > _Employees;
};

#endif // HRSYSTEM_H
